﻿#include "rec_read_avi.h"
#include "cross_com.h"
#include "rec_data_io.h"
#include <stdint.h>
#include "serial_file_com_nonebuf.h"

extern StorageConfig	g_storageCfg;

CRecReadAvi::CRecReadAvi(int clientID,int channel)
{
	m_curPos     = 0;
	m_pIdxBuf    = NULL;
	m_dataOffset = STFS_REC_DATA_OFFSET;
	m_pIdxBuf    = new STFS_REC_IDX[(STFS_REC_DATA_OFFSET - STFS_REC_IDX_OFFSET)/REC_INDEX_LEN];
	m_fileStatus = STFS_REC_WRITTING;

	m_playMode   = REPLAY_NORMAL;
	m_speed      = 1;
	m_stepIFrame = 1;
	m_version    = 0;
	m_fileLen    = 0;

	m_channel    = channel;
	m_clientID   =clientID;
	m_startTime	 = 0;
	m_endTime	 = 0;

	m_recOffset	 = 512;
	m_idxOffset  = 0;
	m_dataOffset = 0;
	m_fileIdx	 = -1;
	m_nBufSize   = SIZE_4MB;
	m_curTime    = 0;
	m_bDataEnd   = true;
	m_clientID   = 0;
	m_stepIFrame = 1;
	m_segIdx         = -1;
	m_fileIdx       =0 ;
	m_noReadCount   = 0;
	m_bDownload     = false;
	m_fileStartLBA  = 0;
	m_bLocalBackup  = false;
	m_data_pkt_size = SIZE_64KB;
	m_frameNO       = 0;

	if( NULL == m_pFile)
	{  
		m_pFile = new CSerialFileComNobuf();
	}
	m_diff_pts = 30;

}

CRecReadAvi::~CRecReadAvi()
{
	if(m_pFile)
	{
		delete m_pFile;
	}
	if(m_pIdxBuf)
	{
		delete [] m_pIdxBuf;
	}

	if( 0 == m_clientID)
	{
		m_pFIFO = NULL;
	}
}

int CRecReadAvi::Open(const char * filename, uint32_t fileIndex,int64_t startTime, int64_t endTime ,bool bClearBuf)
{
	int ret = 0;
	uint32_t fileSpace = SIZE_MB(256);

	if(m_pFile->IsOpened())
	{  
		//当前通道文件已经打开，但是不是同一个文件，则需要先关闭掉文件
		if( 0 != strcmp(m_pFile->get_device_name(),filename))
		{
			m_pFile->Close();
		}
	}

	ret = m_pFile->Open((void*)filename,0,fileSpace,SCSI_RDONLY);
	if(ret < 0  && ret != ERR_FILE_OPENED)
	{ 
		TRACE("Open file %s fail.\n",filename);
		return ret;
	}
	
	int frmIndexSize = STFS_REC_DATA_OFFSET;
	
	m_playMode  = REPLAY_NORMAL;
	
	ret = m_frmIdx.Open(frmIndexSize,STFS_REC_IDX_OFFSET,m_pFile->get_sec_size());

	ret = ReadRecInfo();
	if(ret < 0)
	{
		TRACE_ERR("Read record info ret %d \n",ret);
		return ret;
	}

	m_curPos = STFS_REC_DATA_OFFSET;
	Seek(m_curPos);

	int fifo_size = g_storageCfg.chInfo[m_channel].replay_cache_sz;
	ret = m_pFIFO->Open(m_channel,fifo_size);

	m_curPos = STFS_REC_DATA_OFFSET;

	m_frameNO  = 0;
	m_bDataEnd = false;
	m_curIndex = 0;
	if(m_frameRate >= 0)
	{
		m_diff_pts = 1000 / m_frameRate;
	}

	StartDataIO();
	
	m_fileLen = m_pFile->get_data_size();
	
	return 0;
}

int CRecReadAvi::ReadFrame(uchar_t* frameBuf, uint32_t bufLen)
{
	if(m_pFile->is_closed())
	{   
		if( 0 == m_pFIFO->GetDataSize())
		{
			return ERR_FILE_NOOPEN;
		}
	}

	int ret = 0;
	uint32_t frameSize = 0;
	int wait_count = 300;
	uint32_t data_space = 0;
	LHN_FRAME_H * pHead = (LHN_FRAME_H * ) frameBuf;
	uchar_t * pNaluType = frameBuf + BASE_FRAME_HEAD_LEN + 4;
	uchar_t * pAviBox = frameBuf + BASE_FRAME_HEAD_LEN - 8;
	//由底层，来智能读取缓冲数据
	for(int idx = 0 ; idx < 3; idx++)
	{
		switch (m_playMode)
		{
		case REPLAY_REBACK:
		case REPLAY_FAST:
			frameSize = ret = m_pFIFO->GetFrame(frameBuf,bufLen);
			break;
		default:
			frameSize = ret = m_pFIFO->GetAVIFrame(pAviBox,bufLen);
			break;
		}
	
		if(ret > 0)
		{
			break;
		}
		
		if(m_pFile->is_closed())
		{
			return ERR_FILE_NOOPEN;
		}

		if( ERR_FIFO_NOTENOUGH == ret  || 
			ERR_DATA_AREA      == ret)
		{
			frameSize  = m_pFIFO->GetNextFrmSize();
			while(wait_count)
			{
				if(wait_count == 0)
				{
					TRACE("CH %02d Wait time too long.Free space %u \n",m_channel,data_space);
					PrintTimeMs(m_curTime,0,"last Frame Time");
					return ret;
				}

				CrossSleep(10);

				data_space = m_pFIFO->GetDataSize();
				if((data_space >= frameSize) && (frameSize != 0))
				{
					//TRACE_ERR("CH %02d FIFO_ERR_NOTENOUGH data_space %d data_size %d wait_count %d \n",m_channel,data_space,data_size,wait_count);
					break;
				}

				wait_count--;
			}

			if(wait_count == 0 && idx == 2)
			{
				TRACE_ERR("CH %02d Wait time too long.Free space %u\n",m_channel,data_space);
				m_bDataEnd = true;
				PrintTimeMs(m_curTime,0,"last Frame Time");
				return ERR_DATA_AREA;
			}
		}
	}

	pHead->frameTag = LHNFrameTag;
	
	if( 1 == (pNaluType[0] & 0x1f))
	{
		pHead->frameType = PFrame;
	}
	else
	{
		pHead->frameType = IFrame;
	}

	switch (m_playMode)
	{
	case REPLAY_FAST :
	case REPLAY_REBACK:
		m_lastReadTime  = pHead->pts;
		m_frameNO       = pHead->frameNo;
		break;
	default:
		pHead->pts       = m_frameNO++ * m_diff_pts;
		pHead->frameNo   = m_frameNO;
		m_lastReadTime   = pHead->pts + m_startTime;
		pHead->dataLen   = frameSize - 8;
		break;
	}

	frameSize       = pHead->dataLen + BASE_FRAME_HEAD_LEN;
	m_lastfrmNo     = m_frameNO;

// 	m_frmTool.Init(frameBuf);
// 	if(!m_frmTool.IsEffect())
// 	{
// 		LHN_FRAME_H * pFrm = (LHN_FRAME_H *) (frameBuf);
// 
// 		m_bDataEnd = true;
// 		TRACE_ERR("ch%d FSFrameTag error  len%d  frame pts %lld!\n",
// 			       pFrm->dataLen,pFrm->channel,pFrm->pts);
// 		PrintTimeMs(pFrm->pts,0,"cur Frame Time");
// 		PrintTimeMs(m_curTime,0,"last Frame Time");
// 		CROSS_ASSERT(false);
// 		return 0;
// 	}

// 	if((m_curTime = m_frmTool.GetFrameTime()) >= m_endTime ||
//         m_curTime < m_startTime)//时间超过了录像段的结束时间
// 	{
// 		m_bDataEnd = true;
// 		TRACE_ERR("Time  Over file end. cur offset %d.\n",m_curPos);
// 		PrintTimeMs(m_frmTool.GetFrameTime(),0,"cur Time");
// 		PrintTimeMs(m_endTime,0,"last Frame Time");
// 		return 0;
// 	}
	//TRACE("Get on frame OK!",ret);e
	return frameSize;
}

int CRecReadAvi::ReadFIFONormal()
{
	int ret = 0;
	uchar_t* pbuf = NULL;
	uint32_t   free_size  = m_pFIFO->GetFreeSize();

   //TRACE_CBS("Read To FIFO curoffset %d read_size %d.\n",m_curPos,read_size);
	uint32_t leaf_data = m_fileLen - m_curPos;// m_fileSize - m_cur_offset;
	if(0 == leaf_data )
    {
		m_bDataEnd = true;
		TRACE_ERR("Cur Pos %d fileLen %d   .\n",m_curPos,m_fileLen);
        return ERR_REPLAY_NODATA;
    }

	uint32_t bufSize  = 0;
	pbuf = GetReplayTmpBuf(bufSize);
	uint32_t readSize = 0;
	uint32_t readPos   = m_curPos;
	uint32_t frameSize  = 0;

	if(leaf_data < free_size)
	{
		free_size = leaf_data;
	}

	while( free_size  > 0)
	{
		if(free_size > bufSize )
			readSize = bufSize;
		else
			readSize = free_size;//对齐对64KB

		ret = m_pFile->ReadPos(readPos,pbuf,readSize);
		if(ret < 0)
		{
			goto ERR_OUT;
		}

		readPos  += readSize;
		//剩余空间计算必须实时更新

		ret = m_pFIFO->write(pbuf,readSize);

		free_size -= readSize;
	}

	m_curPos  = readPos;
	return ret ;
ERR_OUT:
	TRACE_ERR("Read data fail.\n");
	return ret;
}

//带有校正偏移的函数
int CRecReadAvi::ReadFIFOForward()	//只读取关键帧数据,具有跳帧处理
{
	int ret = 0;
	//	TRACE("CH%02d fileIndex %d ReadFIFOForward begin index %02d",m_channel,m_fileIdx,m_curIndex);
	unsigned char* pAviBuf  = NULL;
	unsigned char* FrameBuf = NULL;
	LHN_FRAME_H  * pHead   = NULL;
	uint32_t readBufSize = m_pFIFO->GetFreeSize();
	uint32_t offset    = 0;
	uint32_t frmSize   = 0;
	uint32_t dataSize  = 0;
	uint32_t readSize  = 0;
	int		 frmCount  = 0;
	int		 nexIdx    = 0;
	uint32_t bufSize  = 0;

	FrameBuf = GetReplayTmpBuf(bufSize);
	pAviBuf  = FrameBuf + BASE_FRAME_HEAD_LEN - 8;
	pHead    = (LHN_FRAME_H*)FrameBuf;

	CROSS_ASSERT(pAviBuf != NULL);
	m_pFile->Lock();
	uint32_t headLen  = BASE_FRAME_HEAD_LEN - 8;
	uint32_t frmLen   = 0;

	while(dataSize + headLen < readBufSize )
	{
		nexIdx = m_curIndex + m_stepIFrame;
		if((nexIdx) >= m_maxIndex)
		{
			ret = ERR_REPLAY_BUFFULL;
			m_bDataEnd = true;
			break;
		}

		//增加时间结束判断 尽量不超录像段的时候
		if(m_pIdxBuf[nexIdx].tmMS > m_endTime)
		{
			//	TRACE("CH%02d 1-2 Over buffer size.Last idx %d\n",m_channel,nexIdx);//Test Info
			ret = ERR_REPLAY_BUFFULL;
			m_bDataEnd = true;
			break;
		}

		offset = m_pIdxBuf[nexIdx].offset;
		frmSize= m_pIdxBuf[nexIdx].frameLen;

		if(frmSize & 0x01)  //进行偶数字节对齐写入到缓冲当中
		{
			frmSize += 1;
		}

		frmLen = frmSize+ headLen;
		if((dataSize + frmLen) > readBufSize )
		{
			break;
		}

		readSize = GetReadPacketSize(offset,frmSize);
		ret = m_pFile->ReadPos(offset,pAviBuf,readSize,false);
		if(ret < 0)
		{
			TRACE_ERR("CH%02d Read data error offset %d ,size %d. ret %d \n",m_channel,offset,frmSize, ret);
			goto ERR_REC;
		}

	//	//从DataPacket 中解析出I帧
	//	CreateFrameToFIFO(pbuf,readSize);
		pHead->pts      = m_pIdxBuf[nexIdx].tmMS;
		pHead->frameTag = LHNFrameTag;
		pHead->frameNo  = nexIdx * m_frameRate;
		pHead->headLen  = BASE_FRAME_HEAD_LEN;
		pHead->dataLen  = frmSize - 8;

		ret = m_pFIFO->write(FrameBuf,pHead->dataLen + BASE_FRAME_HEAD_LEN);
		if( ret < 0)
		{
			break;
		}

		m_curIndex += m_stepIFrame;
		dataSize   += frmLen + BASE_FRAME_HEAD_LEN - 8;
		frmCount++;
	}

	m_curPos = offset;	//记录最后的Offset
	m_pFile->Unlock();
	return frmCount;

ERR_REC:
	m_pFile->Unlock();
	m_curPos = offset;
	m_bDataEnd = true;
	TRACE_ERR("Read data error . ret %d .\n",ret);
	return ret;
}

int CRecReadAvi::ReadFIFOReback()	//逆向读取关键帧数
{
	int ret = 0;

	//TRACE("CH%02d fileIndex %d ReadFIFOForward begin index %02d",m_channel,m_fileIdx,m_curIndex);
	unsigned char* pAviBuf  = NULL;
	unsigned char* FrameBuf = NULL;
	LHN_FRAME_H  * pHead   = NULL;

	uchar_t* pDataBuf = NULL;
	uint32_t readBufSize = m_pFIFO->GetFreeSize();

	uint32_t offset    = 0;
	uint32_t frmSize   = 0;
	uint32_t dataSize  = 0;
	int		 frmCount  = 0;
	int		 nexIdx    = 0;
	uint32_t readSize  = 0;
	uint32_t bufSize   = 0;

	FrameBuf = GetReplayTmpBuf(bufSize);
	CROSS_ASSERT(FrameBuf != NULL);
	uint32_t headLen  = BASE_FRAME_HEAD_LEN;
	uint32_t frmLen   = 0;
	STFS_REC_IDX * pIdx = NULL;
	
	pAviBuf  = FrameBuf + BASE_FRAME_HEAD_LEN - 8;
	pHead    = (LHN_FRAME_H*)FrameBuf;

	m_pFile->Lock();
	while(dataSize + headLen < readBufSize )
	{
		
		nexIdx = m_curIndex - m_stepIFrame;
		if((nexIdx) < 0)
		{
			ret = ERR_REPLAY_BUFFULL;
			m_bDataEnd = true;
			break;
		}
		pIdx = &m_pIdxBuf[nexIdx];
		//增加时间结束判断 尽量不超录像段的时候
		if(pIdx->tmMS < m_startTime)
		{
			//	TRACE("CH%02d 1-2 Over buffer size.Last idx %d\n",m_channel,nexIdx);//Test Info
			ret = ERR_REPLAY_BUFFULL;
			m_bDataEnd = true;
			break;
		}

		offset  =  pIdx->offset;
		frmSize =  pIdx->frameLen;
		if(frmSize & 0x01)  //进行偶数字节对齐写入到缓冲当中
		{
			frmSize += 1;
		}

		//是否越界
		if((dataSize + frmLen) > readBufSize )
		{
			break;
		}

		readSize = frmSize;
		ret = m_pFile->ReadPos(offset,pAviBuf,readSize,false);
		if(ret < 0)
		{
			TRACE_ERR("CH%02d Read data error offset %d ,size %d. ret %d \n",m_channel,offset,frmSize, ret);
			goto ERR_REC;
		}

		//从DataPacket 中解析出I帧
		PrintTimeMs(m_pIdxBuf[nexIdx].tmMS);

		pHead->pts      = m_pIdxBuf[nexIdx].tmMS;
		pHead->frameTag = LHNFrameTag;
		pHead->frameNo  = nexIdx * m_frameRate;
		pHead->headLen  = BASE_FRAME_HEAD_LEN;
		pHead->dataLen  = frmSize - 8;

		ret = m_pFIFO->write(FrameBuf,frmSize);
		if( ret < 0)
		{
			break;
		}

		m_curIndex -= m_stepIFrame;
		dataSize   += frmSize;
		frmCount++;
	}

	m_curPos = offset;	//记录最后的Offset
	m_pFile->Unlock();
	return frmCount;

ERR_REC:
	m_pFile->Unlock();
	m_curPos   = offset;
	m_bDataEnd = true;
	TRACE_ERR("Read data error . ret %d .\n",ret);
	return ret;
}

//2倍速，技术难度最大
int CRecReadAvi::ReadFIFO2Forward()
{
	return  0;
}

uint32_t  CRecReadAvi::GetReadPacketSize(uint32_t offset,uint32_t frmSize)
{
	uint32_t readSize = SIZE_ROUND_UP(frmSize + m_data_pkt_size ,m_data_pkt_size);
	if(offset +  readSize > m_fileLen )
	{
		readSize = m_fileLen - offset;
	}

	return readSize;
}


//对齐到data packet
uint32_t CRecReadAvi::AlignToDataPacket(uint32_t srcOffset)
{
	CROSS_ASSERT(srcOffset >= m_dataOffset);

	uint32_t diffOffset = srcOffset - m_dataOffset;

	diffOffset = SIZE_ROUND_ALIGN(diffOffset,m_data_pkt_size);
	return  (diffOffset + m_dataOffset);
}




